package com.nnnu.wsnackshop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.nnnu.wsnackshop.exception.ObjectException;
import com.nnnu.wsnackshop.pojo.dto.AddStoreAddressDTO;
import com.nnnu.wsnackshop.pojo.dto.StoreAddressPageDTO;
import com.nnnu.wsnackshop.pojo.dto.UpdateStoreAddressDTO;
import com.nnnu.wsnackshop.pojo.entity.StoreAddresses;
import com.nnnu.wsnackshop.mapper.StoreAddressesMapper;
import com.nnnu.wsnackshop.pojo.vo.StoreAddressVO;
import com.nnnu.wsnackshop.result.PageResult;
import com.nnnu.wsnackshop.service.IStoreAddressesService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <p>
 * 门店地址表 服务实现类
 * </p>
 *
 * @author zk
 * @since 2025-05-19
 */
@Service
@RequiredArgsConstructor
public class StoreAddressesServiceImpl extends ServiceImpl<StoreAddressesMapper, StoreAddresses>
        implements IStoreAddressesService {

    private static final DateTimeFormatter FMT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    @Override

    public PageResult<StoreAddressVO> pageAddresses(@NotNull StoreAddressPageDTO dto) {
        Page<StoreAddresses> page = new Page<>(dto.getPageNum(), dto.getPageSize());
        LambdaQueryWrapper<StoreAddresses> qw = new LambdaQueryWrapper<StoreAddresses>()
                .eq(dto.getStoreId() != null, StoreAddresses::getStoreId, dto.getStoreId())
                .orderByDesc(StoreAddresses::getIsDefault, StoreAddresses::getCreatedAt);
        Page<StoreAddresses> result = baseMapper.selectPage(page, qw);
        List<StoreAddressVO> vos = result.getRecords().stream().map(addr -> {
            StoreAddressVO vo = BeanUtil.toBean(addr, StoreAddressVO.class);
            vo.setCreatedAt(addr.getCreatedAt().format(FMT));
            vo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
            return vo;
        }).collect(Collectors.toList());
        return PageResult.<StoreAddressVO>builder()
                .total(result.getTotal())
                .items(vos)
                .build();
    }

    @Override
    public List<StoreAddressVO> listByStore(Long storeId) {
        List<StoreAddresses> list = baseMapper.selectByStoreId(Math.toIntExact(storeId));
        return list.stream().map(addr -> {
            StoreAddressVO vo = BeanUtil.toBean(addr, StoreAddressVO.class);
            vo.setCreatedAt(addr.getCreatedAt().format(FMT));
            vo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createAddress(AddStoreAddressDTO dto) {
        // 如果设置为默认，则先取消同门店其他默认
        if (dto.getIsDefault() != null && dto.getIsDefault() == 1) {
            baseMapper.update(new StoreAddresses().setIsDefault(0), new LambdaQueryWrapper<StoreAddresses>()
                    .eq(dto.getStoreId() != null, StoreAddresses::getStoreId, dto.getStoreId())
                    .eq(dto.getIsDefault() != null, StoreAddresses::getIsDefault, 1));
        }
        // 插入新地址
        StoreAddresses addr = BeanUtil.copyProperties(dto, StoreAddresses.class);
        baseMapper.insert(addr);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAddress(UpdateStoreAddressDTO dto) {
        StoreAddresses addr = baseMapper.selectById(dto.getId());
        if (addr == null) {
            throw new ObjectException("门店地址不存在: " + dto.getId());
        }
        // 如果要将此地址设为默认，则先取消其他同门店默认
        if (dto.getIsDefault() != null && dto.getIsDefault() == 1) {
            baseMapper.update(new StoreAddresses().setIsDefault(0), new LambdaQueryWrapper<StoreAddresses>()
                    .eq(addr.getStoreId() != null, StoreAddresses::getStoreId, addr.getStoreId())
                    .eq(dto.getIsDefault() != null, StoreAddresses::getIsDefault, 1)
                    .ne(StoreAddresses::getId, dto.getId()));
        }
        // 更新可选字段
        if (dto.getRegion() != null)
            addr.setRegion(dto.getRegion());
        if (dto.getDetail() != null)
            addr.setDetail(dto.getDetail());
        if (dto.getIsDefault() != null)
            addr.setIsDefault(dto.getIsDefault());
        baseMapper.updateById(addr);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAddresses(List<Integer> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ObjectException("待删除的地址ID列表不能为空");
        }
        // 去重
        ids = ids.stream().distinct().toList();

        // 1. 批量查询
        List<StoreAddresses> list = baseMapper.selectBatchIds(ids);

        // 2. 校验：找出不存在的 ID
        Set<Integer> foundIds = list.stream().map(StoreAddresses::getId).collect(Collectors.toSet());
        List<Integer> missing = ids.stream()
                .filter(id -> !foundIds.contains(id))
                .toList();
        if (!missing.isEmpty()) {
            throw new ObjectException("以下地址不存在，无法删除: " + missing);
        }

        // 3. 校验：找出其中的默认地址
        List<Integer> defaultOnes = list.stream()
                .filter(addr -> Objects.equals(addr.getIsDefault(), 1))
                .map(StoreAddresses::getId)
                .toList();
        if (!defaultOnes.isEmpty()) {
            throw new ObjectException("包含默认地址，无法删除: " + defaultOnes);
        }

        // 4. 删除
        baseMapper.deleteBatchIds(ids);
    }

    // 用户端新增方法实现
    @Override
    public StoreAddressVO getDefaultAddress(Long storeId) {
        LambdaQueryWrapper<StoreAddresses> qw = new LambdaQueryWrapper<StoreAddresses>()
                .eq(StoreAddresses::getStoreId, storeId)
                .eq(StoreAddresses::getIsDefault, 1)
                .last("LIMIT 1");
        StoreAddresses address = baseMapper.selectOne(qw);
        if (address == null) {
            return null;
        }
        StoreAddressVO vo = BeanUtil.toBean(address, StoreAddressVO.class);
        vo.setCreatedAt(address.getCreatedAt().format(FMT));
        vo.setUpdatedAt(address.getUpdatedAt().format(FMT));
        return vo;
    }

    @Override
    public StoreAddressVO getAddressDetail(Long id) {
        StoreAddresses address = baseMapper.selectById(id);
        if (address == null) {
            return null;
        }
        StoreAddressVO vo = BeanUtil.toBean(address, StoreAddressVO.class);
        vo.setCreatedAt(address.getCreatedAt().format(FMT));
        vo.setUpdatedAt(address.getUpdatedAt().format(FMT));
        return vo;
    }

    @Override
    public List<StoreAddressVO> batchGetAddresses(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return List.of();
        }
        List<Integer> intIds = ids.stream().map(Long::intValue).collect(Collectors.toList());
        List<StoreAddresses> addresses = baseMapper.selectBatchIds(intIds);
        return addresses.stream().map(addr -> {
            StoreAddressVO vo = BeanUtil.toBean(addr, StoreAddressVO.class);
            vo.setCreatedAt(addr.getCreatedAt().format(FMT));
            vo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
            return vo;
        }).collect(Collectors.toList());
    }

    @Override
    public List<StoreAddressVO> searchAddresses(String keyword, Long storeId) {
        LambdaQueryWrapper<StoreAddresses> qw = new LambdaQueryWrapper<StoreAddresses>();

        if (storeId != null) {
            qw.eq(StoreAddresses::getStoreId, storeId);
        }

        if (StringUtils.hasText(keyword)) {
            qw.and(wrapper -> wrapper
                    .like(StoreAddresses::getRegion, keyword)
                    .or()
                    .like(StoreAddresses::getDetail, keyword));
        }

        qw.orderByDesc(StoreAddresses::getIsDefault, StoreAddresses::getCreatedAt);

        List<StoreAddresses> addresses = baseMapper.selectList(qw);
        return addresses.stream().map(addr -> {
            StoreAddressVO vo = BeanUtil.toBean(addr, StoreAddressVO.class);
            vo.setCreatedAt(addr.getCreatedAt().format(FMT));
            vo.setUpdatedAt(addr.getUpdatedAt().format(FMT));
            return vo;
        }).collect(Collectors.toList());
    }
}
